package com.yjzx.util.common.util;

import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;

/**
 * @author yjzx
 * @date 2024/8/18
 * @description
 */
public class ExceptionUtil {

    /**
     * 抛异常
     *
     * @param exception 异常
     * @throws Exception 异常
     */
    public static <T extends Throwable> void throwException(T exception) throws T {
        throwException(exception == null ? (T) new NullPointerException("异常不存在") : exception, exception == null ? 1 : 0);
    }

    /**
     * 抛异常，去除指定数量的方法栈
     *
     * @param exception 异常
     * @param subNum    去除的栈数量
     * @throws Exception 异常
     */
    public static <T extends Throwable> void throwException(T exception, int subNum) throws T {
        subNum = Math.max(0, subNum);
        if (exception == null) {
            exception = (T) new NullPointerException("异常不存在");
            subNum = 1;
        }
        exception.setStackTrace(ExceptionUtil.getStackTrace(exception.getStackTrace(), subNum));
        throw exception;
    }

    /**
     * 抛异常
     *
     * @param exceptionClass 异常类型
     * @param args           异常参数
     * @param <T>            异常泛型（异常实际类型）
     * @throws T
     */
    public static <T extends Throwable> void throwException(Class<T> exceptionClass, Object... args) throws T {
        throwException(1, exceptionClass, args);
    }

    public static <T extends Throwable> void throwException(int subNum, Class<T> exceptionClass, Object... args) throws T {
        T exception;
        try {
            subNum = Math.max(0, subNum);
            Class<?>[] argsClass = new Class[args.length];
            for (int i = 0; i < args.length; i++) {
                if (args[i] == null) {
                    throwException(new NullPointerException("参数不能为空"));
                } else {
                    argsClass[i] = args[i].getClass();
                }
            }
            exception = exceptionClass.getConstructor(argsClass).newInstance(args);
            subNum += 5;
        } catch (Exception e) {
            exception = (T) new RuntimeException(String.valueOf(exceptionClass) + "类此参数无法正确创建异常" + (args.length == 1 ? String.valueOf(args[0]) : Arrays.toString(args)));
            exception.addSuppressed(e);
            subNum += 1;

        }
        throwException(exception, subNum);
    }


    /**
     * 异常转换为运行异常，并抛出
     *
     * @param exception 实际异常
     */
    public static void throwToRunException(Throwable exception) {
        throwToRunException(exception, RuntimeException.class, exception==null?1:0);
    }

    /**
     * 异常转换为指定运行异常，并抛出
     *
     * @param exception      实际异常
     * @param exceptionClass 指定运行异常类
     */
    public static void throwToRunException(Throwable exception, Class<? extends RuntimeException> exceptionClass) {
        throwToRunException(exception, exceptionClass, exception==null||exceptionClass==null?1:0);
    }

    /**
     * 异常转换为运行异常，并抛出
     *
     * @param exception 实际异常
     * @param subNum    去除的栈数量
     */

    public static void throwToRunException(Throwable exception, int subNum) {
        throwToRunException(exception, RuntimeException.class, exception==null?1:subNum);
    }

    /**
     * 异常转换为指定运行异常，并抛出
     *
     * @param exception      实际异常
     * @param exceptionClass 指定运行异常类
     * @param subNum         去除的栈数量
     */
    public static <T extends RuntimeException> void throwToRunException(Throwable exception, Class<T> exceptionClass, int subNum) {
        if (exception == null){
            throwException(new NullPointerException("异常不存在"),++subNum);
        }else if (exceptionClass == null){
            throwException(new NullPointerException("异常类型不存在"),++subNum);
        }
        exception.setStackTrace(ExceptionUtil.getStackTrace(exception.getStackTrace(), subNum));
        T exceptionT;
        try {
            exceptionT = exceptionClass.getConstructor(Throwable.class).newInstance(exception);
            subNum = 7;
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            exceptionT = (T) new RuntimeException(exception);
        }
        throwException(exceptionT, subNum);
    }

    /**
     * 根据方法栈去除指定数量的方法栈
     *
     * @param trace  方法栈
     * @param subNum 去除的栈数量
     * @return 去除后的方法栈
     */
    public static StackTraceElement[] getStackTrace(StackTraceElement[] trace, int subNum) {
        int length = trace.length;
        subNum = subNum <= 0 ? 0 : Math.min(subNum, length);
        int len = Math.max(length - subNum, 0);
        StackTraceElement[] copy = new StackTraceElement[len];
        System.arraycopy(trace, subNum, copy, 0,
                Math.min(trace.length, len));
        return copy;
    }
}
